﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Seagull.Internal
{
    /// <summary>
    /// 用于寻找指定特性的函数容器
    /// </summary>
    public sealed class MethodAttributeContainer
    {
        static readonly Dictionary<Type, List<MethodInfo>> dicMethods = new();

        private static void Initialization(Type type)
        {
            var items = new List<MethodInfo>();
            var typeCollection = App.EffectiveTypes.Where(x => x.IsClass);
            foreach (var item in typeCollection)
            {
                var methods = item.GetMethods().Where(method => method.GetCustomAttribute(type) is not null);
                items.AddRange(methods);
            }
            dicMethods[type] = items;
        }

        /// <summary>
        /// 根据指定的特性类型返回符合的方法数组；
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetMethodCollection<T>() where T : Attribute
        {
            return GetMethodCollection(typeof(T));
        }

        /// <summary>
        /// 根据指定的特性类型返回符合的方法数组；
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetMethodCollection(Type type)
        {
            if (!dicMethods.ContainsKey(type))
                Initialization(type);
            return dicMethods[type];
        }

        /// <summary>
        /// 根据指定的特性类型并匹配特性规则后，返回符合的方法数组；
        /// </summary>
        /// <typeparam name="T">指定的特性类型</typeparam>
        /// <param name="func">匹配规则</param>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetMethodCollection<T>(Func<T, bool> func) where T : Attribute
        {
            Type type = typeof(T);
            if (!dicMethods.ContainsKey(type))
                Initialization(type);

            var methods = dicMethods[type];
            foreach (var method in methods)
            {
                var attributes = method.GetCustomAttributes<T>();
                foreach (var attribute in attributes)
                {
                    if (func.Invoke(attribute))
                    {
                        yield return method;
                        break;
                    }
                }
            }
        }       
    }
}
